package com.derbysoft.ota.application.translator.rq;

import static com.derbysoft.ota.interfaces.protocol._2009a.TransactionActionType.BOOK;
import static com.derbysoft.ota.interfaces.protocol._2009a.TransactionActionType.INITIATE;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.derbysoft.modules.eip.translator.Translator;
import com.derbysoft.ota.application.util.RequestorIDs;
import com.derbysoft.ota.application.util.UniqueIDTypes;
import com.derbysoft.ota.interfaces.protocol._2009a.HotelResRequestType;
import com.derbysoft.ota.interfaces.protocol._2009a.HotelReservationIDsType;
import com.derbysoft.ota.interfaces.protocol._2009a.HotelReservationType;
import com.derbysoft.ota.interfaces.protocol._2009a.POSType;
import com.derbysoft.ota.interfaces.protocol._2009a.ResGlobalInfoType;
import com.derbysoft.ota.interfaces.protocol._2009a.HotelReservationIDsType.HotelReservationID;
import com.derbysoft.remote.dswitch.generic.constants.TransactionActionType;
import com.derbysoft.remote.dswitch.generic.constants.UniqueIDType;
import com.derbysoft.remote.dswitch.generic.dto.UniqueIDDTO;
import com.derbysoft.remote.dswitch.hotel.dto.HotelReservationDTO;
import com.derbysoft.remote.dswitch.hotel.dto.HotelReservationIDDTO;
import com.derbysoft.remote.dswitch.hotel.dto.HotelReservationRQ;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.googlecode.functionalcollections.FunctionalIterables;

public class HotelReservationRQTranslator implements Translator<HotelResRequestType, HotelReservationRQ> {

	private static Logger logger = LoggerFactory.getLogger(HotelReservationRQTranslator.class);
	
	private Translator<HotelResRequestType, HotelReservationDTO> hotelResRequestTypeTranslator;
	
	
	@Inject
	public HotelReservationRQTranslator(
		Translator<HotelResRequestType, HotelReservationDTO> hotelResRequestTypeTranslator) {
		this.hotelResRequestTypeTranslator = hotelResRequestTypeTranslator;
	}

	@Override
	public HotelReservationRQ translate(HotelResRequestType source) {
		HotelReservationRQ otaReservationRQ = new HotelReservationRQ();
		otaReservationRQ.setResActionType(resActionType(source.getResStatus()));
		otaReservationRQ.setOriginalBuyer(originalBuyer(source.getPOS()));
		otaReservationRQ.setHotelReservationIDs(hotelReservationIDs(source));
		otaReservationRQ.setHotelReservation(hotelReservation(source));
		return otaReservationRQ;
	}

	private TransactionActionType resActionType(
		com.derbysoft.ota.interfaces.protocol._2009a.TransactionActionType resStatus) {
		if (INITIATE == resStatus) {
			return TransactionActionType.INITIATE;
		}  
		if (BOOK == resStatus) {
			return TransactionActionType.BOOK;
		} 
		throw new UnsupportedOperationException("Unsupported transaction action type [" + resStatus +"], we only support Initiate and Book transaction action type.");
	}

	private UniqueIDDTO originalBuyer(POSType pos) {
		return new UniqueIDDTO(RequestorIDs.of(pos).getID(), UniqueIDType.TRAVEL_AGENCY);
	}

	private List<HotelReservationIDDTO> hotelReservationIDs(HotelResRequestType source) {
		HotelReservationIDDTO reservationIDDTO = new HotelReservationIDDTO();
		HotelReservationType reservationType =
			FunctionalIterables.make(
				source.getHotelReservations().getHotelReservation()
			).messagedIterator("Please provide at least 1 hotel reservation").next();
		ResGlobalInfoType globalInfoType = reservationType.getResGlobalInfo();
		if (globalInfoType == null) {
			return Lists.newArrayList();
		}
		if (globalInfoType.getHotelReservationIDs() != null) {
			HotelReservationIDsType reservationIDs = globalInfoType.getHotelReservationIDs();
			HotelReservationID detected = FunctionalIterables.make(reservationIDs.getHotelReservationID()).detect(UniqueIDTypes.reservation());
			if (detected == null) {
				logger.warn("Discarded invalid reservation ids [ " + reservationIDs.getHotelReservationID() + "]");
				return Lists.newArrayList();
			}
			reservationIDDTO.setResIDType(UniqueIDType.RESERVATION);
			reservationIDDTO.setResIDValue(Preconditions.checkNotNull(detected.getResIDValue(), "ResIDValue required."));
			Preconditions.checkNotNull(detected.getResIDSource(), "ResID_Source required.");
			return Lists.newArrayList(reservationIDDTO);
		}
		return Lists.newArrayList();
	}

	private HotelReservationDTO hotelReservation(HotelResRequestType source) {
		return hotelResRequestTypeTranslator.translate(source) ;
	}


}
